package com.zhanglijie.base.sync.Lock;

import java.lang.reflect.Field;

import javax.management.relation.RoleUnresolved;

import lombok.Data;
import lombok.SneakyThrows;
import sun.misc.Unsafe;

/**
 * @author zhanglijie
 * @version 1.0
 * @since 1.1.0 2022/6/9 0009 0:11
 */
@Data
public class MySynchronized {
    //默认开启偏向锁
    private boolean UseBiasedLock = true;
    private static MyLock myLock = new MyLock();
    static BiasedLocking biasedLocking = new BiasedLocking();
    public static ThreadLocal<LockRecord> threadLocal = new ThreadLocal(){
           @SneakyThrows
           @Override
        protected LockRecord initialValue(){
               MarkWord markWord = null;
               MarkWord owner = null;
               LockRecord lockRecord = new LockRecord(markWord,owner);
               return lockRecord;
           }
    };

    /**
     * 加锁入口
     */
    public void monitorEnter() throws NoSuchFieldException, CloneNotSupportedException {
        /**
         * 锁升级后续实现
         * 无锁-》偏向锁-》轻量级锁-》重量级锁
         */
        if(UseBiasedLock){//是否开启偏向锁
             fast_Enter();
        }else{
            //走轻量级锁
            slowEnter();
       }
    }

    /**
     * 解锁流程
     */

    public void monitorExit() throws NoSuchFieldException {
        MarkWord markWord = myLock.getMarkWord();
        String biasedLock = markWord.getBiasedLock();
        String lockFlag = markWord.getLockFlag();
        long threadId = markWord.getThreadId();
        long id = Thread.currentThread()
            .getId();
        //偏向锁退出
        if(biasedLock!=null && "1".equals(biasedLock) && lockFlag!=null && "01".equals(lockFlag)){
            if(threadId!=id){
                throw new RuntimeException("not  thread myself can not release lock!!!");
            }else{
                //这个threadId修改成-1
                return;
            }
        }else{
            slowExit(markWord);
        }
    }

    /**
     * 轻量级锁退出
     * @param markWord
     */
    private void slowExit(MarkWord markWord) throws NoSuchFieldException {
        //需要讲markword还原
        LockRecord lockRecord = threadLocal.get();
        //将当前栈帧中的markword还回去
        MarkWord head = lockRecord.getMarkWord();
        if(head!=null){
            //cas还原markword
            Unsafe unsafe = MyUnsafe.getUnsafe();
            Field markWord1 = myLock.getClass().getDeclaredField("markWord");
            long offset = unsafe.objectFieldOffset(markWord1);
            Object objectVolatile = unsafe.getObjectVolatile(myLock, offset);
            boolean isOk = unsafe.compareAndSwapObject(myLock, offset, objectVolatile, head);
            if(isOk){
                lockRecord.setOwner(null);
                lockRecord.setMarkWord(null);
                markWord.setLockFlag("01");
                return;
            }else{
                //cas修改失败  轻量级锁膨胀
                inflateExit();
            }
        }
    }

    /**
     * 膨胀释放锁
     * @throws NoSuchFieldException
     */
    private void inflateExit() throws NoSuchFieldException {
        //进行膨胀过程，具体碰撞过程待实现
        ObjectMonitor objectMonitor = inflate();
        //进入重量级锁
        objectMonitor.exit(myLock);
    }
    /**
     * 偏向锁加锁
     * @throws NoSuchFieldException
     */
    private void fast_Enter() throws NoSuchFieldException, CloneNotSupportedException {
        //如果开启了偏向锁功能 默认开启
        if(UseBiasedLock){
            //获取偏向锁
            boolean var = biasedLocking.revokeAndRebias(myLock);
            if(var) return;
        }
        slowEnter();
    }

    private void inflateEnter() throws NoSuchFieldException {
        //进行膨胀过程，具体碰撞过程待实现
        ObjectMonitor objectMonitor = inflate();//todo 创建重量级锁对象有了就直接返回 其实一个线程创建成功别的可以直接使用
        //进入重量级锁
        objectMonitor.entery(myLock);
    }

    private void slowEnter() throws NoSuchFieldException, CloneNotSupportedException {
        //这里有很多 逻辑
        MarkWord markWord = myLock.getMarkWord();
        String lockFlag = markWord.getLockFlag();
        if(lockFlag!=null && lockFlag.equals("01")){
            //目前正处于无所或者偏向锁状态
            //设置默认值
            markWord.setThreadId(-1);
            markWord.setBiasedLock(null);
            //变更lockRecord指针
            Unsafe unsafe = Unsafe.getUnsafe();
            Field ptrLockRecord = markWord.getClass().getDeclaredField("ptrLockRecord");
            long offset = unsafe.objectFieldOffset(ptrLockRecord);
            Object origin = unsafe.getObjectVolatile(markWord, offset);
            LockRecord lockRecord = threadLocal.get();
            boolean isOk = unsafe.compareAndSwapObject(markWord, offset, origin, lockRecord);
            if(isOk){
                MarkWord markWordClone = (MarkWord) markWord.clone();
                lockRecord.setMarkWord(markWordClone);
                markWord.setLockFlag("00");
                lockRecord.setOwner(markWord);
                return;
            }
        }else if(lockFlag!=null && lockFlag.equals("00")){
            //此时已经是轻量级锁状态
            markWord.setThreadId(-1);
            markWord.setBiasedLock(null);
            //先获取当前线程的lockRecord
            LockRecord lockRecord = threadLocal.get();
            LockRecord ptrLockRecord = markWord.getPtrLockRecord();
            if(lockRecord !=null && ptrLockRecord !=null && lockRecord==ptrLockRecord){
                return;//已经有锁了
            }
        }
        //膨胀入口
        inflateEnter();//这个如果 上面return了就不会碰撞

    }

    /**
     * 锁碰撞过程
     * @return
     */
    private ObjectMonitor inflate() throws NoSuchFieldException {
        //膨胀过程，膨胀成功返回ObjectMonitor对象
        for(;;){
            //如果已经膨胀成功了
            MarkWord markWord = myLock.getMarkWord();
            ObjectMonitor ptrMonitor = markWord.getPtrMonitor();
            //1.如果已经膨胀完毕（已经程池ptrMonitro对象了）
            if(ptrMonitor!=null){
                return ptrMonitor;
            }
            //2.正在膨胀中,continue
            String status = markWord.getStatus();
            if(status!=null && "inflating".equals(status)){
                continue;
            }
            //3.当前是轻量级锁
            LockRecord ptrLockRecord = markWord.getPtrLockRecord();
            String lockFlag = markWord.getLockFlag();
            if(lockFlag!=null && "00".equals(lockFlag) && ptrLockRecord!=null ){
                //cas 自旋更改markword状态
                Unsafe unsafe = Unsafe.getUnsafe();
                Field status1 = markWord.getClass().getDeclaredField("status");
                long offset = unsafe.objectFieldOffset(status1);
                Object origin = unsafe.getObjectVolatile(markWord, offset);
                boolean isOk = unsafe.compareAndSwapObject(markWord, offset, origin, "inflating");
                //更新失败
                if(!isOk)continue;
                //更新成功
                ObjectMonitor objectMonitor = new ObjectMonitor();
                markWord.setPtrMonitor(objectMonitor);
                markWord.setLockFlag("10");
                markWord.setPtrLockRecord(null);
                return objectMonitor;

            }

        }

    }

}
